home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / SpriteWorld 2.0 ƒ / SpriteWorld Examples / Scrolling Demo / Scrolling Demo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-05  |  16.3 KB  |  646 lines  |  [TEXT/KAHL]

  1. ///--------------------------------------------------------------------------------------
  2. // Scrolling Demo.c
  3. //
  4. // By Vern Jensen. Created in August of 1995
  5. ///--------------------------------------------------------------------------------------
  6.  
  7.  
  8. #include <SWFPSReport.h>
  9. #include <SWIncludes.h>
  10. #include <SWGameUtils.h>
  11.  
  12. #include "SWApplication.h"
  13. #include "Scrolling Demo.h"
  14.  
  15.  
  16. #define    kFullScreenWindow            false        // Try me full screen!
  17. #define kWorldRectInset                0            // Make the SpriteWorld smaller?
  18. #define    kInterlacedMode                true        // Turns Interlaced mode on/off
  19. #define kSyncToVBL                    false        // Sync SpriteWorld to VBL?
  20. #define kMaxFPS                        30            // Set to 0 for unrestricted speed
  21.  
  22.     
  23. #define    kSpriteMoveDelta            20            // Try 5, 10, 20, or 40
  24. #define kDiamondSpace                8            // How far apart the diamonds are spaced
  25.                                                 // (try 1!)
  26.  
  27. #define kSpriteMoveDistance            80            // How far the sprite can move from
  28.                                                 // the center of the screen, in pixels.
  29.                                                 // Try making this value higher!
  30.  
  31.     // Number of ticks to wait before changing tile image; 0 = change every frame
  32. #define kDiamondFrameRate            8            // How often diamond tiles change frames
  33. #define kWallFrameRate                120            // How often wall changes frames
  34.  
  35. #define kBWPictResIDOffset            100
  36. #define kTileWidth                    40
  37. #define kTileHeight                    40
  38. #define kTileMapRows                100
  39. #define kTileMapCols                150
  40.  
  41. #define kStartRow                    5            // Starting position of sprite
  42. #define kStartCol                    5            // in tile col and row
  43.  
  44.  
  45. #define    kLeftArrowKey                0x7B
  46. #define    kRightArrowKey                0x7C
  47. #define    kDownArrowKey                0x7D
  48. #define    kUpArrowKey                    0x7E
  49.  
  50. #define    kLeftKeyPad                    0x56
  51. #define    kRightKeyPad                0x58
  52. #define    kDownKeyPad                    0x54
  53. #define    kUpKeyPad                    0x5B
  54.  
  55. #define kEscKey                        0x35
  56.  
  57.  
  58. #define kNoKey                        0
  59. #define kLeftKey                    1
  60. #define kUpKey                        2
  61. #define kRightKey                    3
  62. #define kDownKey                    4
  63.  
  64.  
  65. enum tileIDs
  66. {
  67.     kWallTile,
  68.     kLastWallTile,
  69.     kGrassTile,
  70.     kBlackTile,
  71.     kDiamondTile,
  72.     kDiamondTile2,
  73.     kLastDiamondTile,
  74.     
  75.     kTunnelTile1,
  76.     kTunnelTile2,
  77.     kTunnelTile3,
  78.     kTunnelTile4,
  79.     kTunnelTile5,
  80.     kTunnelTile6,
  81.     kWireTile1,
  82.     kWireTile2,
  83.     
  84.     kMaxNumTiles
  85. };
  86.  
  87.  
  88.  
  89. /***********/
  90. /* Globals */
  91. /***********/
  92.  
  93. SpriteWorldPtr    gSpriteWorldP;
  94. TileMapPtr        gTileMap;
  95. SpritePtr        gSimpleSpriteP;
  96. WindowPtr        gWindowP;
  97. Rect            gScreenMidRect;
  98.  
  99. short            gKeys[4];        // Stores keys in order that they were pressed
  100. short            gNumKeys = 0;    // Number of keys in gKeys array
  101.  
  102.  
  103.  
  104.  
  105. ///--------------------------------------------------------------------------------------
  106. // Main
  107. ///--------------------------------------------------------------------------------------
  108.  
  109. void    main( void )
  110. {
  111.     Initialize(kNumberOfMoreMastersCalls);
  112.     
  113.     if (SWHasSystem7())
  114.     {
  115.         AllowKeyUpEvents();    // Part of SWGameUtils.c
  116.         SetCursor(*GetCursor(watchCursor));
  117.         
  118.         CreateSpriteWorld();
  119.         CreateSprites();
  120.         
  121.         SetCursor(&qd.arrow);
  122.         HideCursor();
  123.         
  124.         SetUpAnimation();
  125.         RunAnimation();
  126.         ShutDown();
  127.         
  128.         RestoreEventMask();    // Call this after AllowKeyUpEvents
  129.     }
  130.     else
  131.     {
  132.         CantRunOnThisMachine();
  133.     }
  134. }
  135.  
  136.  
  137. ///--------------------------------------------------------------------------------------
  138. // CreateSpriteWorld
  139. ///--------------------------------------------------------------------------------------
  140.  
  141.  
  142. void    CreateSpriteWorld( void )
  143. {
  144.     Rect        offscreenRect, worldRect, windRect;
  145.     RgnHandle    mBarUpdateRgn;
  146.     OSErr        err;
  147.     short        row, col;
  148.     short        resIDOffset;
  149.     
  150.     gWindowP = GetNewCWindow(kWindowResID, NULL, (WindowPtr)-1L);
  151.     
  152.     if (gWindowP != NULL)
  153.     {
  154.         if (kFullScreenWindow == true)
  155.         {
  156.             SizeWindow(gWindowP, qd.screenBits.bounds.right, 
  157.                     qd.screenBits.bounds.bottom, false);
  158.             MoveWindow(gWindowP, 0, 0, false);
  159.         }
  160.         else
  161.         {
  162.                 // Center window in screen
  163.             windRect = gWindowP->portRect;
  164.             CenterRect(&windRect, &qd.screenBits.bounds);
  165.             MoveWindow(gWindowP, windRect.left, windRect.top, false);
  166.         }
  167.         
  168.         ShowWindow(gWindowP);
  169.         SetPort(gWindowP);
  170.         mBarUpdateRgn = HideMenuBar(gWindowP); // Must be done *after* showing window!
  171.         EraseRgn(mBarUpdateRgn);
  172.         
  173.         if (kInterlacedMode)
  174.             PaintRect(&gWindowP->portRect);    // Blacken window for Interlaced mode
  175.     }
  176.     else
  177.         CantFindResource();
  178.     
  179.     
  180.     err = SWEnterSpriteWorld();
  181.     FatalError(err);
  182.     
  183.     
  184.     worldRect = gWindowP->portRect;
  185.     InsetRect(&worldRect, kWorldRectInset, kWorldRectInset);
  186.     
  187.     
  188.         // Set size of offscreen area
  189.     offscreenRect = worldRect;
  190.     OffsetRect(&offscreenRect, -offscreenRect.left, -offscreenRect.top);
  191.     
  192.  
  193.         // Make offscreen area evenly divisible by tile width & height
  194.     if ( (offscreenRect.right/kTileWidth)*kTileWidth != offscreenRect.right)
  195.         offscreenRect.right = (offscreenRect.right/kTileWidth)*kTileWidth + kTileWidth;
  196.     
  197.     if ( (offscreenRect.bottom/kTileHeight)*kTileHeight != offscreenRect.bottom)
  198.         offscreenRect.bottom = (offscreenRect.bottom/kTileHeight)*kTileHeight + kTileHeight;
  199.  
  200.     
  201.         // Create the scrolling sprite world
  202.     err = SWCreateSpriteWorldFromWindow(&gSpriteWorldP, (CWindowPtr)gWindowP, 
  203.             &worldRect, &offscreenRect);
  204.     FatalError(err);
  205.     
  206.     
  207.  
  208.     err = SWInitTiling(gSpriteWorldP, kTileHeight, kTileWidth, kMaxNumTiles);
  209.     FatalError(err);
  210.     
  211.     err = SWCreateTileMap(gSpriteWorldP, &gTileMap, kTileMapRows, kTileMapCols);
  212.     FatalError(err);
  213.     
  214.  
  215.         // Determine whether to load B&W or color graphics
  216.     if (gSpriteWorldP->pixelDepth == 1)
  217.         resIDOffset = kBWPictResIDOffset;
  218.     else
  219.         resIDOffset = 0;
  220.  
  221.         // Load first set of tiles
  222.     err = SWLoadTilesFromPictResource(
  223.         gSpriteWorldP, 
  224.         kWallTile,                // startTileID 
  225.         kLastDiamondTile,        // endTileID
  226.         200 + resIDOffset,        // pictResID
  227.         0,                        // maskResID
  228.         kNoMask,                // maskType
  229.         1,                        // horizBorderWidth
  230.         1);                        // vertBorderHeight
  231.     FatalError(err);
  232.     
  233.         // Load masked set of tiles
  234.     err = SWLoadTilesFromPictResource(
  235.         gSpriteWorldP, 
  236.         kTunnelTile1,            // startTileID 
  237.         kWireTile2,                // endTileID
  238.         201 + resIDOffset,        // pictResID
  239.         401,                    // maskResID
  240.         kFatMask,                // maskType
  241.         1,                        // horizBorderWidth
  242.         1);                        // vertBorderHeight
  243.     FatalError(err);
  244.  
  245.     
  246.         // Set up tileMap
  247.     for (row = 0; row < kTileMapRows; row++)
  248.     {
  249.         for (col = 0; col < kTileMapCols; col++)
  250.         {
  251.             if (row == 0 || col == 0 || row == kTileMapRows-1 || col == kTileMapCols-1)
  252.                 gTileMap[row][col] = kWallTile;
  253.             else if (row > kTileMapRows / 2)
  254.                 gTileMap[row][col] = kWireTile1;
  255.             else if ((row/kDiamondSpace)*kDiamondSpace == row && 
  256.                      (col/kDiamondSpace)*kDiamondSpace == col)
  257.                 gTileMap[row][col] = kDiamondTile;
  258.             else
  259.                 gTileMap[row][col] = kGrassTile;
  260.         }
  261.     }
  262.     
  263.  
  264.         // Add tunnel to tileMap
  265.     row = kTileMapRows / 2;
  266.  
  267.     for (col = 1; col < kTileMapCols-1; col += 2)
  268.     {
  269.         gTileMap[row][col] = kTunnelTile1;
  270.         gTileMap[row][col+1] = kTunnelTile2;
  271.         gTileMap[row+1][col] = kTunnelTile4;
  272.         gTileMap[row+1][col+1] = kTunnelTile5;
  273.     }
  274. }
  275.     
  276.  
  277. ///--------------------------------------------------------------------------------------
  278. // CreateSprites
  279. ///--------------------------------------------------------------------------------------
  280.  
  281. void    CreateSprites( void )
  282. {
  283.     SpriteLayerPtr        spriteLayerP;
  284.     OSErr                err;
  285.     
  286.     
  287.         // Create the sprite layer
  288.     err = SWCreateSpriteLayer(&spriteLayerP);
  289.     FatalError(err);
  290.     
  291.         // Create the main sprite
  292.     err = SWCreateSpriteFromCicnResource(gSpriteWorldP, &gSimpleSpriteP, NULL, 
  293.             128, 1, kFatMask);    
  294.     FatalError(err);
  295.     
  296.     
  297.             // Set up the sprite
  298.     SWSetSpriteUnderTiles(gSimpleSpriteP, true);
  299.     SWSetSpriteMoveProc(gSimpleSpriteP, KeySpriteMoveProc);
  300.     SWSetSpriteLocation(gSimpleSpriteP, kStartCol * kTileWidth, kStartRow * kTileHeight);
  301.     SWSetSpriteMoveDelta(gSimpleSpriteP, 0, 0);
  302.     
  303.         // Set the sprite's drawProc
  304.     if (gSpriteWorldP->pixelDepth == 8)        // If in 256 colors
  305.     {
  306.         if (kInterlacedMode)
  307.             SWSetSpriteDrawProc(gSimpleSpriteP, BP8BitInterlacedMaskDrawProc);
  308.         else
  309.             SWSetSpriteDrawProc(gSimpleSpriteP, BlitPixie8BitMaskDrawProc);
  310.     }
  311.     else                                    // Not 256 colors
  312.     {
  313. #if !SW_PPC            // No BlitPixieAllBit in PPC compiles
  314.             // Use interlaced drawProcs unless in B&W, where interlacing is ugly
  315.         if (kInterlacedMode && gSpriteWorldP->pixelDepth != 1)
  316.             SWSetSpriteDrawProc(gSimpleSpriteP, BPAllBitInterlacedMaskDrawProc);
  317.         else
  318.             SWSetSpriteDrawProc(gSimpleSpriteP, BlitPixieAllBitMaskDrawProc);
  319. #endif
  320.     }
  321.     
  322.     SWAddSprite(spriteLayerP, gSimpleSpriteP);
  323.     SWAddSpriteLayer(gSpriteWorldP, spriteLayerP);
  324.     
  325.     SWLockSpriteWorld(gSpriteWorldP);
  326. }
  327.  
  328.  
  329. ///--------------------------------------------------------------------------------------
  330. // SetUpAnimation
  331. ///--------------------------------------------------------------------------------------
  332.  
  333. void    SetUpAnimation( void )
  334. {
  335.     Rect        moveBoundsRect;
  336.     
  337.         // Set up data used by the SmoothScrollingWorldMoveProc
  338.     gScreenMidRect = gSimpleSpriteP->curFrameP->frameRect;
  339.     CenterRect( &gScreenMidRect, &gSpriteWorldP->backRect );
  340.     
  341.     SWSetSpriteWorldMaxFPS(gSpriteWorldP, kMaxFPS);
  342.     SWSyncSpriteWorldToVBL(gSpriteWorldP, kSyncToVBL);
  343.     
  344.         // movement boundary = size of tileMap
  345.     SetRect(&moveBoundsRect, 0,0, kTileMapCols * kTileWidth, kTileMapRows * kTileHeight);
  346.     
  347.     SWSetScrollingWorldMoveBounds(gSpriteWorldP, &moveBoundsRect);
  348.     SWSetScrollingWorldMoveProc(gSpriteWorldP, SmoothScrollingWorldMoveProc, gSimpleSpriteP);
  349.     
  350.     SWSetTileChangeProc(gSpriteWorldP, TileChangeProc);
  351.     
  352.         // Move visScrollRect to starting sprite position
  353.     SWMoveVisScrollRect(gSpriteWorldP, 
  354.         gSpriteWorldP->followSpriteP->destFrameRect.left - gSpriteWorldP->backRect.right/2,
  355.         gSpriteWorldP->followSpriteP->destFrameRect.top - gSpriteWorldP->backRect.bottom/2);
  356.     
  357.  
  358.     if (gSpriteWorldP->pixelDepth == 8)        // If in 256 colors
  359.     {
  360.         if (kInterlacedMode)
  361.         {
  362.             SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BP8BitInterlacedRectDrawProc);
  363.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BP8BitInterlacedRectDrawProc);
  364.             SWSetTileMaskDrawProc(gSpriteWorldP, BP8BitInterlacedPartialMaskDrawProc);
  365.         }
  366.         else
  367.         {
  368.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BlitPixie8BitRectDrawProc);
  369.             SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BlitPixie8BitRectDrawProc);
  370.             SWSetTileMaskDrawProc(gSpriteWorldP, BlitPixie8BitPartialMaskDrawProc);
  371.         }
  372.     }
  373.     else                                    // Not 256 colors
  374.     {
  375. #if !SW_PPC            // No BlitPixieAllBit in PPC compiles
  376.         if (kInterlacedMode && gSpriteWorldP->pixelDepth != 1)
  377.         {
  378.                 // Use interlaced drawProcs unless in B&W, where interlacing is ugly
  379.             SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BPAllBitInterlacedRectDrawProc);
  380.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BPAllBitInterlacedRectDrawProc);
  381.             SWSetTileMaskDrawProc(gSpriteWorldP, BPAllBitInterlacedPartialMaskDrawProc);
  382.         }
  383.         else
  384.         {
  385.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BlitPixieAllBitRectDrawProc);
  386.             SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BlitPixieAllBitRectDrawProc);
  387.             SWSetTileMaskDrawProc(gSpriteWorldP, BlitPixieAllBitPartialMaskDrawProc);
  388.         }
  389. #endif
  390.     }
  391.     
  392.     
  393.     ForeColor(blackColor);
  394.     BackColor(whiteColor);
  395.     
  396.     SWDrawTilesInBackground(gSpriteWorldP);
  397.     SWUpdateScrollingSpriteWorld(gSpriteWorldP, true);
  398. }
  399.  
  400.  
  401. ///--------------------------------------------------------------------------------------
  402. //  RunAnimation
  403. ///--------------------------------------------------------------------------------------
  404.  
  405.     
  406. void    RunAnimation( void )
  407. {
  408.     unsigned long        frames;
  409.     
  410.     frames = 0;
  411.     StartTimer();
  412.     
  413.  
  414.     while (!Button())
  415.     {
  416.         SWProcessScrollingSpriteWorld(gSpriteWorldP);
  417.         SWAnimateScrollingSpriteWorld(gSpriteWorldP);
  418.         
  419.         if (gSpriteWorldP->frameHasOccured)
  420.             frames++;
  421.     }
  422.     
  423.     
  424.     ShowMenuBar(gWindowP);
  425.     ShowResults(frames);
  426. }
  427.  
  428.  
  429. ///--------------------------------------------------------------------------------------
  430. //  ShutDown (clean up and dispose of the SpriteWorld)
  431. ///--------------------------------------------------------------------------------------
  432.  
  433.  
  434. void    ShutDown( void )
  435. {
  436.     SWDisposeSpriteWorld(gSpriteWorldP);
  437.     SWExitSpriteWorld();
  438.     
  439.     FlushEvents(everyEvent, 0);
  440.     ShowCursor();
  441. }
  442.  
  443.  
  444. ///--------------------------------------------------------------------------------------
  445. //  TileChangeProc
  446. ///--------------------------------------------------------------------------------------
  447.  
  448.  
  449. void    TileChangeProc(
  450.     SpriteWorldPtr spriteWorldP)
  451. {
  452.     short            curImage;
  453.     static short    wallDelay = 0, diamondDelay = 0;
  454.     static short    oldTicks = 0;
  455.     short            ticksPassed, ticks;
  456.     
  457.         // Initialize oldTicks the first time this function is called
  458.     if (oldTicks == 0)
  459.         oldTicks = TickCount();
  460.     
  461.     ticks = TickCount();
  462.     ticksPassed = ticks - oldTicks;        // Number of ticks passed since last call
  463.     oldTicks = ticks;
  464.     
  465.         // kWallTile
  466.     wallDelay += ticksPassed;
  467.     if (wallDelay >= kWallFrameRate)
  468.     {
  469.         curImage = spriteWorldP->curTileImage[kWallTile];
  470.         if (curImage < kLastWallTile)
  471.             curImage++;
  472.         else
  473.             curImage = kWallTile;
  474.         
  475.         SWChangeTileImage(spriteWorldP, kWallTile, curImage);
  476.         wallDelay = 0;
  477.     }
  478.     
  479.     
  480.         // kDiamondTile
  481.     diamondDelay += ticksPassed;
  482.     if (diamondDelay >= kDiamondFrameRate)
  483.     {
  484.         curImage = spriteWorldP->curTileImage[kDiamondTile];
  485.         if (curImage < kLastDiamondTile)
  486.             curImage++;
  487.         else
  488.             curImage = kDiamondTile;
  489.         
  490.         SWChangeTileImage(spriteWorldP, kDiamondTile, curImage);
  491.         diamondDelay = 0;
  492.     }
  493. }
  494.  
  495.  
  496. ///--------------------------------------------------------------------------------------
  497. //  KeySpriteMoveProc
  498. ///--------------------------------------------------------------------------------------
  499.  
  500.  
  501. void KeySpriteMoveProc(SpritePtr srcSpriteP)
  502. {
  503.     short    row, col;
  504.     short    rowDelta, colDelta;
  505.     short    tile;
  506.     
  507.     UpdateKeys();    // Put the latest key values in the keys structure
  508.     
  509.     
  510.     row = srcSpriteP->destFrameRect.top / kTileHeight;
  511.     col = srcSpriteP->destFrameRect.left / kTileWidth;
  512.  
  513.     if (row * kTileHeight == srcSpriteP->destFrameRect.top &&
  514.         col * kTileWidth == srcSpriteP->destFrameRect.left)
  515.     {
  516.         tile = gTileMap[row][col];
  517.         
  518.             // Leave black trail behind sprite
  519.         if (tile == kGrassTile || tile == kDiamondTile)
  520.             SWDrawTile(gSpriteWorldP, row, col, kBlackTile);
  521.         else if (tile == kTunnelTile2 || tile == kTunnelTile5 || tile == kWireTile1)
  522.             SWDrawTile(gSpriteWorldP, row, col, tile+1);
  523.         
  524.  
  525.         rowDelta = 0;
  526.         colDelta = 0;
  527.         
  528.         if (gKeys[0] == kLeftKey)
  529.             colDelta = -1;
  530.         else if (gKeys[0] == kRightKey)
  531.             colDelta = 1;
  532.         else if (gKeys[0] == kUpKey)
  533.             rowDelta = -1;
  534.         else if (gKeys[0] == kDownKey)
  535.             rowDelta = 1;
  536.         
  537.                 
  538.         
  539.         tile = gTileMap[row + rowDelta][col + colDelta];
  540.         
  541.         if (tile != kWallTile && tile != kTunnelTile1 && tile != kTunnelTile4)
  542.         {
  543.             srcSpriteP->vertMoveDelta = rowDelta * kSpriteMoveDelta;
  544.             srcSpriteP->horizMoveDelta = colDelta * kSpriteMoveDelta;
  545.         }
  546.         else
  547.         {
  548.             srcSpriteP->vertMoveDelta = 0;
  549.             srcSpriteP->horizMoveDelta = 0;
  550.         }
  551.     }
  552.     
  553.     SWOffsetSprite(srcSpriteP, srcSpriteP->horizMoveDelta, srcSpriteP->vertMoveDelta);
  554. }
  555.  
  556.  
  557. ///--------------------------------------------------------------------------------------
  558. //  SmoothScrollingWorldMoveProc - our scrolling WorldMoveProc
  559. ///--------------------------------------------------------------------------------------
  560.  
  561.  
  562. void    SmoothScrollingWorldMoveProc(
  563.     SpriteWorldPtr spriteWorldP,
  564.     SpritePtr followSpriteP)
  565. {    
  566.     short    screenMidRectTop, screenMidRectLeft;
  567.     
  568.     screenMidRectTop = gScreenMidRect.top + spriteWorldP->visScrollRect.top;
  569.     screenMidRectLeft = gScreenMidRect.left + spriteWorldP->visScrollRect.left;
  570.     
  571.     
  572.     spriteWorldP->horizScrollDelta = (kSpriteMoveDelta * 
  573.         (followSpriteP->destFrameRect.left - screenMidRectLeft) ) / kSpriteMoveDistance;
  574.     
  575.     spriteWorldP->vertScrollDelta = (kSpriteMoveDelta * 
  576.         (followSpriteP->destFrameRect.top - screenMidRectTop) ) / kSpriteMoveDistance;
  577.     
  578.     if (kInterlacedMode)
  579.         spriteWorldP->vertScrollDelta = spriteWorldP->vertScrollDelta>>1<<1;
  580. }
  581.  
  582.  
  583. ///--------------------------------------------------------------------------------------
  584. //  UpdateKeys (Put the latest key values in the keys structure)
  585. ///--------------------------------------------------------------------------------------
  586.  
  587.  
  588. void    UpdateKeys( void )
  589. {
  590.     EventRecord        event;
  591.     short            theKey, newKey, n;
  592.     
  593.     
  594.     while ( GetOSEvent( (keyUpMask | keyDownMask), &event ) )
  595.     {
  596.         theKey = (event.message & keyCodeMask) >> 8;
  597.         
  598.         switch (theKey)
  599.         {
  600.             case kLeftArrowKey:
  601.             case kLeftKeyPad:
  602.                 newKey = kLeftKey;
  603.                 break;
  604.             case kRightArrowKey:
  605.             case kRightKeyPad:
  606.                 newKey = kRightKey;
  607.                 break;
  608.             case kDownArrowKey:
  609.             case kDownKeyPad:
  610.                 newKey = kDownKey;
  611.                 break;
  612.             case kUpArrowKey:
  613.             case kUpKeyPad:
  614.                 newKey = kUpKey;
  615.                 break;
  616.             default:
  617.                 newKey = kNoKey;
  618.         }
  619.  
  620.         if (newKey)
  621.         {
  622.             if (event.what == keyDown)
  623.             {
  624.                     // Store keys in order pressed
  625.                 for (n = gNumKeys; n > 0; n--)
  626.                     gKeys[n] = gKeys[n-1];
  627.                 gKeys[0] = newKey;
  628.                 gNumKeys++;
  629.             }
  630.             else if (event.what == keyUp)
  631.             {
  632.                     // Remove key from list
  633.                 gNumKeys--;
  634.                 for (n = 0; gKeys[n] != newKey; n++);
  635.                 while (n < gNumKeys)
  636.                 {
  637.                     gKeys[n] = gKeys[n+1];
  638.                     n++;
  639.                 }
  640.  
  641.                 gKeys[gNumKeys] = 0;
  642.             }
  643.         }
  644.     }
  645. }
  646.